package com.aispeech.asr.clib.decoder;

import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class AudioDecoder {
    private static IAudioDecoder iAudioDecoder = null;
    private long ptDecoder;
    private boolean used = false; //如果一次都没有start过，不需要delete，会crash

    public AudioDecoder() {
        this(16000);
    }

    public AudioDecoder(int sampleRate) {
        ptDecoder = iAudioDecoder.audio_decoder_new(sampleRate);

        if (ptDecoder <= 0)
            throw new RuntimeException("audio_decoder_new failed. ptDecoder: " + ptDecoder);
    }

    public static void initialize() {
        iAudioDecoder = Native.load("decoder", IAudioDecoder.class);
        log.info(String.format("AudioDecoder library loaded."));
    }

    public int start(EAudioCodec codecType, int sampleRate, int channel, int sampleBytes) {
        used = true;
//        log.info("[ AudioDecoder.start ] type: {}, rate: {}, channel: {}, bytes: {}", codecType.value(), sampleRate, channel, sampleBytes);
        return iAudioDecoder.audio_decoder_start(ptDecoder, codecType.value(), sampleRate, channel, sampleBytes);
    }

    public byte[] feed(byte[] data, int length) {
        int len = data.length;

        if (len > 0) {
            PointerByReference ptOutput = new PointerByReference();
            IntByReference ptLenOutput = new IntByReference();

            int ret = iAudioDecoder.audio_decoder_feed(ptDecoder, data, length, ptOutput, ptLenOutput);

//            log.info("feed length: {}", ptLenOutput.getValue());

            if (ret != 0) {
                log.error("audio decode failed. feed return code: {}", ret);
                return new byte[]{};
            } else if (ptLenOutput.getValue() > 0) {
                return ptOutput.getValue().getByteArray(0, ptLenOutput.getValue());
            } else {
                log.warn("decoded length is zero");
                return new byte[]{};
            }
        } else {
            log.warn("data length too short");
            return new byte[]{};
        }
    }

    public byte[] stop() {
        PointerByReference ptOutput = new PointerByReference();
        IntByReference ptLenOutput = new IntByReference();

        int ret = iAudioDecoder.audio_decdoer_feed_end(ptDecoder, ptOutput, ptLenOutput);

        if (ret != 0) {
            log.error("audio decode failed. feed return code: {}", ret);
            return new byte[]{};
        } else if (ptLenOutput.getValue() > 0) {
            return ptOutput.getValue().getByteArray(0, ptLenOutput.getValue());
        } else {
            return new byte[]{};
        }
    }

    public void destroy() {
        if (used && ptDecoder > 0)
            iAudioDecoder.audio_decoder_delete(ptDecoder);

        ptDecoder = 0;
    }
}
